import { sp, Tween, UITransform, v3 } from "cc";
import { EffectDamage } from "../../model/report/EffectDamage";
import { ISkillReport } from "../../model/report/ISkillReport";
import { ISkillReportHit } from "../../model/report/ISkillReportHit";
import { SkillAnimatorHitEffectDamage } from "./SkillAnimatorHitEffectDamage";
import { oops } from "db://oops-framework/core/Oops";
import { ViewUtil } from "db://oops-framework/core/utils/ViewUtil";
import { smc } from "../../../../common/ecs/SingletonModuleComp";
import { BattleType } from "../../../scene/SceneEvent";
import { BulletView } from "../effect/ballistic/BulletView";
import { EffectRecovery } from "../../../scene/model/EffectRecovery";
import { EffectBuff } from "../../model/report/EffectBuff";
import { EffectImmune } from "../../model/report/EffectImmune";
import { EffectShield } from "../../model/report/EffectShield";
import { SkillAnimatorHitEffectRecovery } from "./SkillAnimatorHitEffectRecovery";
import { SkillAnimatorHitEffectBuff } from "./SkillAnimatorHitEffectBuff";
import { SkillAnimatorHitEffectShield } from "./SkillAnimatorHitEffectShield";

/** 
 * 技能战报动画逻辑
 * 设计思路：
 * 1、自定义技能动画逻辑与自定义效果计算逻辑分离是为了后续将计算逻辑直接复制到服务器做数值验证用 
 * 2、模板可实现自定义释放、弹道、受击、飘血提示动画
 * 
 * 注意问题：
 * 1、受击动画播放打断，不触发动画完成事件
 */
export class SkillAnimator {
    /** 战报数据 */
    isr: ISkillReport = null!;
    /** 动画播放完成 */
    onComplete: Function = null!;
    protected hitCount: number = 0;
    protected startIndex: number = null!;
    /** 施放动画（通用） */
    casting() {
        this.hitCount = 0;

        if (this.isr.sc == null) {
            for (let index = 0; index < this.isr.hits.length; index++) {
                const element = this.isr.hits[index];
                this.onRoleHit(element, index);
            }
        }
        else {
            // 判断是否是近战
            if (this.isr.skill.SkillModel.table.near) {
                this.moveto();
            }
            // 如果是远程，直接播放攻击动作
            else {
                this.attack();
            }
        }
    }
    /**
    * 受击事件触发
    * 1、受击特效
    * 2、生命变化提示
    */
    protected onRoleHit(hit: ISkillReportHit, delay: number = 0) {
        // 伤害效果
        if (hit.effect instanceof EffectDamage) {
            SkillAnimatorHitEffectDamage.play(this.isr, hit.target, hit.effect, this.onEffectComplete.bind(this));
        }
        // 恢复效果
        else if (hit.effect instanceof EffectRecovery) {
            SkillAnimatorHitEffectRecovery.play(this.isr, hit.target, hit.effect, this.onEffectComplete.bind(this));
        }
        // 状态效果
        else if (hit.effect instanceof EffectBuff) {
            SkillAnimatorHitEffectBuff.play(this.isr, hit.target, hit.effect, this.onEffectComplete.bind(this), delay);
        }
        // 护盾效果
        else if (hit.effect instanceof EffectShield) {
            SkillAnimatorHitEffectShield.play(this.isr, hit.target, hit.effect, this.onEffectComplete.bind(this));
        }
        // 免控效果
        else if (hit.effect instanceof EffectImmune) {
            // SkillAnimatorHitEffectImmune.play(this.isr, hit.target, hit.effect, this.onEffectComplete.bind(this));
            console.warn("免控效果：todo");
        }
    }
    protected onEffectComplete(type: string = "onEffectComplete") {
        this.hitCount++;
        var maxCount = this.isr.sc == null ? this.isr.hits.length : this.isr.hits.length + 1;
        // console.warn(type, this.hitCount, ":", maxCount);
        if (this.hitCount == maxCount) {
            // 清理动画战报数据
            this.isr.hits.splice(0, this.isr.hits.length);
            // 施放技能动画流程完成
            this.onComplete && this.onComplete();
        }
    }

    protected moveto() {
        if (this.isr.caster) {
            this.startIndex = this.isr.caster!.RoleView.node.parent!.getSiblingIndex();
            this.isr.caster!.RoleView.node.parent!.setSiblingIndex(this.isr.target.RoleView.node.parent!.getSiblingIndex());
            if (this.isr.hits.length > 1) {
                var wPos = this.isr.target.RoleView.node.parent!.parent!.getChildByName("c")!.getComponent(UITransform)!.convertToWorldSpaceAR(v3(0, 0, 0));
                var tPos = this.isr.caster.RoleView.node.parent!.getComponent(UITransform)!.convertToNodeSpaceAR(v3(wPos.x, wPos.y));
                var toX = tPos.x;
                var toY = tPos.y;
            } else {
                var wPos = this.isr.target.RoleView.node.parent!.getComponent(UITransform)!.convertToWorldSpaceAR(v3(0, 0, 0));
                var tPos = this.isr.caster.RoleView.node.parent!.getComponent(UITransform)!.convertToNodeSpaceAR(v3(wPos.x, wPos.y));
                var toX = tPos.x > 0 ? tPos.x - 100 : tPos.x + 100;
                var toY = tPos.y;
            }

            let tw = new Tween(this.isr.caster.RoleView.node);
            tw.to(0.1 / oops.game.getTimeScale(), { position: v3(toX, toY, 0) });
            tw.call(() => {
                this.attack();
            })
            tw.start();
        }
    }
    private moveback() {
        let tw = new Tween(this.isr.caster?.RoleView.node);
        tw.to(0.1 / oops.game.getTimeScale(), { position: v3(0, 0, 0) });
        tw.call(() => {
            this.isr.caster?.RoleView?.node?.parent?.setSiblingIndex(this.startIndex);
            this.startIndex = null!;
        })
        tw.start();
        this.onEffectComplete("moveback");
    }

    // 技能释放动作
    protected attack() {
        if (this.isr.caster) {
            this.isr.caster.RoleView.animator.onAttack = this.onAttack.bind(this);
            this.isr.caster.RoleView.animator.onAttackComplete = this.onAttackComplete.bind(this);
            this.isr.caster.RoleView.animator.onSkillComplete = this.onAttackComplete.bind(this);

            if (this.isr.skill.SkillModel.table.skill_type == 2) {
                if (this.isr.skill.SkillModel.table.id > 20000) {
                    this.isr.caster.RoleView.animator.attack();
                } else {
                    this.isr.caster.RoleView.animator.skill();
                }
            }
            else {
                this.isr.caster.RoleView.animator.attack();
            }
        }
    }

    /** 
  * 攻击动画事件触发 
  * 1、有弹道动画优先播放
  * 2、无弹道触发目标受击流程
  */
    protected onAttack() {
        var isBallistic = this.isr.skill.SkillModel.effectBallisticPath;
        if (isBallistic) {
            this.animBallistic(isBallistic);
        }
        // 瞬发技能
        else {
            for (let i = 0; i < this.isr.hits.length; i++) {
                const hit = this.isr.hits[i];
                this.onRoleHit(hit);
            }
        }
    }

    protected onAttackComplete() {
        if (this.isr.skill.SkillModel.table.near) {
            this.moveback()
        } else {
            this.onEffectComplete();
        }
    }
    /** 弹道动画（多态） */
    protected animBallistic(isBallistic: string) {
        this.isr.hits.forEach(hit => {
            let target_rv = hit.target.RoleView;
            if (!target_rv?.animator || !target_rv?.node) {
                this.onRoleHit(hit);
                return
            }
            let end = target_rv.animator.getHitPos();
            end = end.add(target_rv.node.parent!.position);

            var path = `game/role/loop`;
            var node = ViewUtil.createPrefabNode(path);
            switch (hit.target.RoleModel.battleType) {
                case BattleType.Scene:
                    node.parent = smc.scene.MapView.effect_top;
                    break;
                case BattleType.Boss:
                   // node.parent = smc.boss.BossMapView.effect_top;
                    console.warn("弹道动画：boss todo");
                    break;
                case BattleType.Tower:
                   // node.parent = smc.tower.TowerMapView.effect_top;

                    console.warn("弹道动画：塔 todo");
                    break;
                default:
                    break;

            }

            var comp = node.addComponent(BulletView);
            var _spine: sp.Skeleton = node.getChildByName("spine")?.getComponent(sp.Skeleton)!;
            oops.res.load(isBallistic, sp.SkeletonData, (err: Error | null, sd: sp.SkeletonData) => {
                if (err) {
                    console.error(`动画名为【${isBallistic}】的角色资源不存在`);
                    return;
                }

                _spine.skeletonData = sd;
                _spine.setAnimation(0, "animation", true);

                var attacker_rv = this.isr.caster!.RoleView;

                var start = attacker_rv.animator.getAttackPos();
                start = start.add(attacker_rv.node.parent!.position);

                comp.fire(start, target_rv.node.parent!, 1000 * oops.game.getTimeScale(), () => {
                    // 释放弹道箭
                    node.destroy();
                    this.onRoleHit(hit);
                });
            });
        });
    }
}